#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>
#include <string.h>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
class Shader
{
public:
	unsigned int ID;
	Shader(const char* vertexPath, const char* fragmentPath) 
	{
		ID = 0;
		string vertexCode, fragmentCode;
		ifstream vShaderFile, fShaderFile;

		vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
		fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
		try
		{
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);
			stringstream vShaderStream, fShaderSteam;
			vShaderStream << vShaderFile.rdbuf();
			fShaderSteam << fShaderFile.rdbuf();
			vShaderFile.close();
			fShaderFile.close();
			vertexCode = vShaderStream.str();
			fragmentCode = fShaderSteam.str();
		}
		catch (const std::exception&)
		{
			cout << "error read" << endl;
		}

		const char* vShaderSource = vertexCode.c_str();
		const char* fShaderSource = fragmentCode.c_str();

		unsigned int vertexShader, fragmentShader;
		vertexShader = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertexShader, 1, &vShaderSource, NULL);
		glCompileShader(vertexShader);
		checkCompileError(vertexShader, 1);

		fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragmentShader, 1, &fShaderSource, NULL);
		glCompileShader(fragmentShader);
		checkCompileError(fragmentShader, 1);

		ID = glCreateProgram();
		glAttachShader(ID, vertexShader);
		glAttachShader(ID, fragmentShader);
		glLinkProgram(ID);
		checkCompileError(ID, 2);

		glDeleteShader(vertexShader);
		glDeleteShader(fragmentShader);
	}
	void use() 
	{
		glUseProgram(ID);
	}
	void setBool(const string &name, bool value) 
	{
		int location = glGetUniformLocation(ID, name.c_str());
		glUniform1i(location, (int)value);
	}
	void setInt(const string &name, int value) 
	{
		int location = glGetUniformLocation(ID, name.c_str());
		glUniform1i(location, value);
	}
	void setFloat(const string &name, float value) 
	{
		int location = glGetUniformLocation(ID, name.c_str());
		glUniform1f(location, value);
	}

	void setColor(const string &name, float r, float g, float b, float a)
	{
		int location = glGetUniformLocation(ID, name.c_str());
		glUniform4f(location, r, g, b, a);
	}

	void setVec2(const string &name, float x, float y) 
	{
		int location = glGetUniformLocation(ID, name.c_str());
		glUniform2f(location, x, y);
	}
	~Shader() 
	{
		if (ID != 0) 
		{
			glDeleteProgram(ID);
		}
	}

private:
	void checkCompileError(unsigned int handler, int type) 
	{
		int success;
		if (type == 1) 
		{
			glGetShaderiv(handler, GL_COMPILE_STATUS, &success);
			if (!success) 
			{
				char info[512];
				glGetShaderInfoLog(handler, 512, NULL, info);
				cout << "compile shader error: \n " << info << "\n----------------------------------" << endl;
			}
		}
		else 
		{
			glGetProgramiv(handler, GL_LINK_STATUS, &success);
			if (!success)
			{
				char info[512];
				glGetProgramInfoLog(handler, 512, NULL, info);
				cout << "link program error: \n " << info << "\n----------------------------------" << endl;
			}
		}
	}
};
#endif